const proxyName = "代理模式";
// - DOMAIN,ad.com,REJECT
// - DOMAIN-SUFFIX,google.com,auto
// - DOMAIN-KEYWORD,google,auto
// - DOMAIN-REGEX,^abc.*com,PROXY

const myrules = [
  //"DOMAIN-SUFFIX,okx.com,JP-自动选择",
  "PROCESS-NAME,tailscale.exe,DIRECT",
  "PROCESS-NAME,tailscaled.exe,DIRECT",
  "PROCESS-NAME,tailscale,DIRECT",
  "PROCESS-NAME,tailscaled,DIRECT",
  "PROCESS-NAME,Telegram.exe,telegram-自动选择",
  "PROCESS-NAME,yt-dlp.exe,youtube-自动选择",
  "PROCESS-NAME,yt-dlp-gui.exe,youtube-自动选择",
  //"PROCESS-NAME-REGEX,.*\.exe,DIRECT",
  "DOMAIN-SUFFIX,telegram.org,telegram-自动选择",
  "DOMAIN-SUFFIX,spotify.com,SG-自动选择",
  "DOMAIN-SUFFIX,x.com,SG-自动选择",
  "DOMAIN-SUFFIX,okx.com,TW-自动选择",
  //"DOMAIN-SUFFIX,youtube.com,youtube-自动选择",
  "DOMAIN-KEYWORD,mihomo,代理模式",
  "DOMAIN-KEYWORD,metacubex,代理模式",
  "DOMAIN-KEYWORD,cdn, DIRECT",
  //"DOMAIN-KEYWORD,cursor, 国外-自动选择",
  "DOMAIN-KEYWORD,ccccc, 测试",
]
var suffixZidong = [
  'metacubex', 'serv00.com', 'xxxtik.com', '987322.xyz',
  'googlevideo.com', 'speedtest.net', 'labondemand.com', 'dopus.com',
  'xn--fhqu06a8m1asto.icu', 'subscription.und32w4732.top', 'v2ex.com',
  'gstatic.com']
for (let value of suffixZidong) {
  myrules.push("DOMAIN-SUFFIX," + value + ",代理模式")
}
var suffixGuowai = ['fikfap.com', 'fikfap-media-prod.b-cdn.net',
  'siliconflow.com', 'cloud-hk.siliconflow.cn',
  'deepseek.com', 'chatgpt.com', 'openai.com', 'google.com', 'googleapis.com',
  'x.ai', 'aitech.io']
for (let value of suffixGuowai) {
  myrules.push("DOMAIN-SUFFIX," + value + ",国外-自动选择")
}

var suffixZhilian = ['steamcdn-a.akamaihd.net', 'steamserver.net',
  'lancache.steamcontent.com', 'mashibing.com']
for (let value of suffixZhilian) {
  myrules.push("DOMAIN-SUFFIX," + value + ",DIRECT")
}

// 代理组最大倍率
const multipliers = { "*": 1 };
// 剔除代理节点名称中不含倍率信息的节点
const multipliersOnly = false;
// 正则表达式
const regex = /(\d+(\.\d*)?) *?([xX✕✖⨉]|倍)+/m;
//过滤节点文本
const filterText = ['到期', '剩余', '问题'];

function filterNode(config) {
  const removed = []; // 过滤后不含任何节点将被移除的group
  config["proxy-groups"] = (config["proxy-groups"] ?? [])
    .map(group => {
      if (multipliers["*"] || multipliers[group?.name]) {
        const beilv = multipliers["*"] ? 1 : multipliers[group.name]
        group["proxies"] = (group["proxies"] ?? []).filter(proxy => {
          //过滤名称
          if (filterText.some(text => proxy.includes(text))) {
            return false;
          }
          //如果类型是select, 则不过滤
          if (group.type === "select") {
            return true;
          }
          const multiplier = regex.exec(proxy)?.[1];
          return multipliersOnly
            ? multiplier !== undefined && Number(multiplier) <= beilv
            : multiplier === undefined || Number(multiplier) <= beilv;
        });
        if (group["proxies"]?.length > 0) {
          return group;
        }
        removed.push(group.name);
      } else {
        return group;
      }
    })
    .filter(Boolean);
  if (removed.length > 0) {
    // 移除代理组的引用
    config["proxy-groups"].forEach(group => { group["proxies"] = group["proxies"].filter(proxy => !removed.includes(proxy)); });
    // 移除规则的引用
    config["rules"] = (config["rules"] ?? []).filter(rule => rule && removed.every(name => !rule.endsWith(name) && !rule.endsWith(`${name},no-resolve`)));
  }
  return config;
}

function main(params) {
  if (!params.proxies) return params;
  //重写代理组
  overwriteProxyGroups(params);
  //重写Rule
  overwriteRules(params);
  //重写DNS
  overwriteDns(params);
  //过滤高倍率节点
  filterNode(params);
  return params;
}

//覆写规则
function overwriteRules(params) {
  //console.log('params.rules', params.rules)
  //去除myrules中不存在的分组
  let groups = params["proxy-groups"]
  console.log('params.groups:'+ groups[0])
  myrules.forEach((rule, index) => {
    const parts = rule.split(",");
    const group = parts[2];
    //如果是no-resolve,DIRECT,REJECT则跳过
    if (["no-resolve", "DIRECT", "REJECT"].includes(group)) {
      return;
    }
    if (!params["proxy-groups"].some(e => e.name === group)) {
        myrules[index] = parts[0] + "," + parts[1] + ",代理模式";
    }
  });
  const rules = [
    ...myrules,
    "RULE-SET,reject,⛔广告拦截",
    "RULE-SET,direct,DIRECT",
    "RULE-SET,cncidr,DIRECT",
    "RULE-SET,private,DIRECT",
    "RULE-SET,lancidr,DIRECT",
    "GEOIP,LAN,DIRECT,no-resolve",
    "GEOIP,CN,DIRECT,no-resolve",
    "RULE-SET,applications,DIRECT",
    "RULE-SET,tld-not-cn," + proxyName,
    "RULE-SET,google," + proxyName,
    "RULE-SET,icloud," + proxyName,
    "RULE-SET,apple," + proxyName,
    "RULE-SET,gfw," + proxyName,
    "RULE-SET,greatfire," + proxyName,
    "RULE-SET,telegramcidr," + proxyName,
    "RULE-SET,proxy," + proxyName,
    "MATCH,🐟漏网之鱼",
    ...params.rules,
  ];
  const ruleProviders = {
    reject: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/reject.txt",
      path: "./ruleset/reject.yaml",
      interval: 86400,
    },
    icloud: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/icloud.txt",
      path: "./ruleset/icloud.yaml",
      interval: 86400,
    },
    apple: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/apple.txt",
      path: "./ruleset/apple.yaml",
      interval: 86400,
    },
    google: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/google.txt",
      path: "./ruleset/google.yaml",
      interval: 86400,
    },
    proxy: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/proxy.txt",
      path: "./ruleset/proxy.yaml",
      interval: 86400,
    },
    direct: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/direct.txt",
      path: "./ruleset/direct.yaml",
      interval: 86400,
    },
    private: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/private.txt",
      path: "./ruleset/private.yaml",
      interval: 86400,
    },
    gfw: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/gfw.txt",
      path: "./ruleset/gfw.yaml",
      interval: 86400,
    },
    greatfire: {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/greatfire.txt",
      path: "./ruleset/greatfire.yaml",
      interval: 86400,
    },
    "tld-not-cn": {
      type: "http",
      behavior: "domain",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/tld-not-cn.txt",
      path: "./ruleset/tld-not-cn.yaml",
      interval: 86400,
    },
    telegramcidr: {
      type: "http",
      behavior: "ipcidr",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/telegramcidr.txt",
      path: "./ruleset/telegramcidr.yaml",
      interval: 86400,
    },
    cncidr: {
      type: "http",
      behavior: "ipcidr",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/cncidr.txt",
      path: "./ruleset/cncidr.yaml",
      interval: 86400,
    },
    lancidr: {
      type: "http",
      behavior: "ipcidr",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/lancidr.txt",
      path: "./ruleset/lancidr.yaml",
      interval: 86400,
    },
    applications: {
      type: "http",
      behavior: "classical",
      url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/applications.txt",
      path: "./ruleset/applications.yaml",
      interval: 86400,
    },
  };
  params["rule-providers"] = ruleProviders;
  params["rules"] = rules;
}
//覆写代理组
function overwriteProxyGroups(params) {
  // 所有代理
  const allProxies = params["proxies"].map((e) => e.name);
  // 自动选择代理组，按地区分组选延迟最低
  const autoProxyGroupRegexs = [
    { name: "HK-自动选择", regex: /香港|HK|Hong|HongKong|🇭🇰/ },
    { name: "TW-自动选择", regex: /台湾|TW|Taiwan|Wan|🇨🇳|🇹🇼/ },
    { name: "SG-自动选择", regex: /新加坡|狮城|SG|Singapore|🇸🇬/ },
    { name: "JP-自动选择", regex: /日本|JP|Japan|🇯🇵/ },
    { name: "US-自动选择", regex: /美国|US|USA|United States|America|🇺🇸/ },
    { name: "UK-自动选择", regex: /英国|UK|United Kingdom|Kingdom|🇺k/ },
    { name: "IN-自动选择", regex: /印度|IN|India|🇮🇳/ },
    { name: "KR-自动选择", regex: /韩国|KR|Korea|🇰🇷/ },
    { name: "DE-自动选择", regex: /德国|DE|Germany|🇩🇪/ },
    { name: "NL-自动选择", regex: /荷兰|NL|Netherlands|🇳🇱/ },
    { name: "CH-自动选择", regex: /瑞士|CH|Switzerland|🇨🇭/ },
    { name: "CA-自动选择", regex: /加拿大|CA|Canada|🇨🇦/ },
    { name: "AU-自动选择", regex: /澳大利亚|AU|Australia|🇦🇺/ },
    { name: "FR-自动选择", regex: /法国|FR|France|🇫🇷/ },
    { name: "BR-自动选择", regex: /巴西|BR|Brazil|🇧🇷/ },
    { name: "RU-自动选择", regex: /俄罗斯|RU|Russia|🇷🇺/ },
    { name: "SE-自动选择", regex: /瑞典|SE|Sweden|🇸🇪/ },
    { name: "Dubai-自动选择", regex: /迪拜|Dubai|🇦🇪/ },
    { name: "IT-自动选择", regex: /意大利|IT|Italy|🇮🇹/ },
    { name: "KZ-自动选择", regex: /哈萨克斯坦|KZ|Kazakhstan|🇰🇿/ },
    { name: "ID-自动选择", regex: /印度尼西亚|ID|Indonesia|🇮🇩/ },
    { name: "UA-自动选择", regex: /乌克兰|Ukraine|🇺🇦/ },
    { name: "VN-自动选择", regex: /越南|Vietnam|🇻🇳/ },
    { name: "TH-自动选择", regex: /泰国|Thailand|🇹🇭/ },
    { name: "PH-自动选择", regex: /菲律宾|Philippines|🇵🇭/ },
    { name: "MY-自动选择", regex: /马来西亚|Malaysia|🇲🇾/ },
    { name: "PK-自动选择", regex: /巴基斯坦|Pakistan|🇵🇰/ },
    { name: "TR-自动选择", regex: /土耳其|Turkey|🇹🇷/ },
    { name: "低倍率-自动选择", regex: /0\./ },
  ];
  // 获取未分组的代理
  let unGroupProxies = allProxies.filter((item) => {
    return !autoProxyGroupRegexs.some((groupRegex) => groupRegex.regex.test(item));
  });
  autoProxyGroupRegexs.push({ name: "国外-自动选择", regex: /^(?!.*(香港|HK|Hong|🇭🇰|台湾|TW|Taiwan|Wan|🇨🇳|🇹🇼)).*$/ })

  const autoProxyGroups = autoProxyGroupRegexs
    .map((item) => ({
      name: item.name,
      type: "url-test",
      url: "http://www.gstatic.com/generate_204",
      //间隔多长时间进行一次测试,单位为秒
      interval: 300,
      //容差,新的最低延迟的代理延迟大于之前选择的节点延迟减去容差值时,才会切换节点,默认0,单位ms
      tolerance: 100,
      proxies: getProxiesByRegex(params, item.regex),
      hidden: item.name !== "低倍率-自动选择" ? true : false,
    }))
    .filter((item) => item.proxies.length > 0 || item.name === "低倍率-自动选择");
  //添加特殊分组
  autoProxyGroups.push({
    name: "未指定分组",
    type: "url-test",
    url: "http://www.gstatic.com/generate_204",
    //间隔多长时间进行一次测试,单位为秒
    interval: 300,
    //容差,新的最低延迟的代理延迟大于之前选择的节点延迟减去容差值时,才会切换节点,默认0,单位ms
    tolerance: 100,
    proxies: unGroupProxies
  });
  // autoProxyGroups.push({
  //     name: "ALL-自动选择",
  //     type: "url-test",
  //     url: "http://www.gstatic.com/generate_204",
  //     //间隔多长时间进行一次测试,单位为秒
  //     interval: 300,
  //     //容差,新的最低延迟的代理延迟大于之前选择的节点延迟减去容差值时,才会切换节点,默认0,单位ms
  //     tolerance: 100,
  //     proxies: allProxies
  // });
  autoProxyGroups.push({
    name: "youtube-自动选择",
    type: "url-test",
    url: "https://www.youtube.com",
    //间隔多长时间进行一次测试,单位为秒
    interval: 300,
    //容差,新的最低延迟的代理延迟大于之前选择的节点延迟减去容差值时,才会切换节点,默认0,单位ms
    tolerance: 100,
    proxies: allProxies,
    hidden: true,
  });
  autoProxyGroups.push({
    name: "telegram-自动选择",
    type: "url-test",
    url: "https://telegram.org",
    //间隔多长时间进行一次测试,单位为秒
    interval: 300,
    //容差,新的最低延迟的代理延迟大于之前选择的节点延迟减去容差值时,才会切换节点,默认0,单位ms
    tolerance: 100,
    proxies: allProxies,
    hidden: true
  });
  const groups = [
    {
      name: proxyName,
      type: "select",
      url: "http://www.gstatic.com/generate_204",
      //icon: "https://fastly.jsdelivr.net/gh/clash-verge-rev/clash-verge-rev.github.io@main/docs/assets/icons/adjust.svg",
      proxies: [
        "自动选择",
        "手动选择",
        "负载均衡(散列)",
        "负载均衡(轮询)",
        "按国家选择",
        "低倍率-自动选择",
      ],
    },
    {
      name: "手动选择",
      type: "select",
      proxies: allProxies,
    },
    {
      name: "自动选择",
      type: "url-test",
      //icon: "https://fastly.jsdelivr.net/gh/clash-verge-rev/clash-verge-rev.github.io@main/docs/assets/icons/speed.svg",
      proxies: allProxies,
    },
    {
      name: "按国家选择",
      type: "select",
      proxies: [],
    },
    {
      name: "负载均衡(散列)",
      type: "load-balance",
      url: "http://www.gstatic.com/generate_204",
      //icon: "https://fastly.jsdelivr.net/gh/clash-verge-rev/clash-verge-rev.github.io@main/docs/assets/icons/balance.svg",
      interval: 300,
      "max-failed-times": 3,
      strategy: "consistent-hashing",
      lazy: true,
      proxies: allProxies,
    },
    {
      name: "负载均衡(轮询)",
      type: "load-balance",
      url: "http://www.gstatic.com/generate_204",
      //icon: "https://fastly.jsdelivr.net/gh/clash-verge-rev/clash-verge-rev.github.io@main/docs/assets/icons/merry_go.svg",
      interval: 300,
      "max-failed-times": 3,
      strategy: "round-robin",
      lazy: true,
      proxies: allProxies,
    },
    {
      name: "🐟漏网之鱼",
      type: "select",
      proxies: ["DIRECT", proxyName],
    },
    {
      name: "⛔广告拦截",
      type: "select",
      proxies: ["REJECT", "DIRECT", proxyName],
    },
  ];
  //把国家分组添加到自动选择
  autoProxyGroups.length &&
    groups[3].proxies.unshift(...autoProxyGroups.map((item) => item.name));
  groups.push(...autoProxyGroups);
  //添加params自带的分组, 排除已有的分组
  params["proxy-groups"].forEach((item) => {
    if (!groups.some((e) => e.name === item.name)) {
      groups.push(item);
    }
  });
  params["proxy-groups"] = groups;
}
//防止dns泄露
function overwriteDns(params) {
  const cnDnsList = [
    "https://223.5.5.5/dns-query",
    "https://1.12.12.12/dns-query",
  ];
  const trustDnsList = [
    'https://dns.cloudflare.com/dns-query',
    'https://dns.google/dns-query',
    'https://doh.apad.pro/dns-query',
    'https://1.0.0.1/dns-query',
    'https://208.67.222.222/dns-query',
  ];
  // const notionDns = 'tls://dns.jerryw.cn'
  // const notionUrls = [
  //     'http-inputs-notion.splunkcloud.com',
  //     '+.notion-static.com',
  //     '+.notion.com',
  //     '+.notion.new',
  //     '+.notion.site',
  //     '+.notion.so',
  // ]
  // const combinedUrls = notionUrls.join(',');
  const dnsOptions = {
    enable: true,
    "prefer-h3": false, // 如果DNS服务器支持DoH3会优先使用h3
    "default-nameserver": cnDnsList, // 用于解析其他DNS服务器、和节点的域名, 必须为IP, 可为加密DNS。注意这个只用来解析节点和其他的dns，其他网络请求不归他管
    nameserver: trustDnsList, // 其他网络请求都归他管

    // 这个用于覆盖上面的 nameserver
    "nameserver-policy": {
      //[combinedUrls]: notionDns,
      "geosite:cn": cnDnsList,
      "+.<tailnet-name>.ts.net": "100.100.100.100",
      //"geosite:geolocation-!cn": trustDnsList,
      // 如果你有一些内网使用的DNS，应该定义在这里，多个域名用英文逗号分割
      // '+.公司域名.com, www.4399.com, +.baidu.com': '10.0.0.1'
    },
    fallback: trustDnsList,
    "fallback-filter": {
      geoip: true,
      //除了 geoip-code 配置的国家 IP, 其他的 IP 结果会被视为污染 geoip-code 配置的国家的结果会直接采用，否则将采用 fallback结果
      "geoip-code": "CN",
      //geosite 列表的内容被视为已污染，匹配到 geosite 的域名，将只使用 fallback解析，不去使用 nameserver
      geosite: ["gfw"],
      ipcidr: ["240.0.0.0/4"],
      domain: ["+.google.com", "+.facebook.com", "+.youtube.com"],
    },
  };

  // GitHub加速前缀
  const githubPrefix = "https://fastgh.lainbo.com/";

  // GEO数据GitHub资源原始下载地址
  const rawGeoxURLs = {
    geoip:
      "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip-lite.dat",
    geosite:
      "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat",
    mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country-lite.mmdb",
  };

  // 生成带有加速前缀的GEO数据资源对象
  const accelURLs = Object.fromEntries(
    Object.entries(rawGeoxURLs).map(([key, githubUrl]) => [
      key,
      `${githubPrefix}${githubUrl}`,
    ])
  );

  const otherOptions = {
    "unified-delay": true,
    "tcp-concurrent": true,
    profile: {
      "store-selected": true,
      "store-fake-ip": true,
    },
    sniffer: {
      enable: true,
      sniff: {
        TLS: {
          ports: [443, 8443],
        },
        HTTP: {
          ports: [80, "8080-8880"],
          "override-destination": true,
        },
      },
    },
    "geodata-mode": true,
    "geox-url": accelURLs,
  };

  params.dns = { ...params.dns, ...dnsOptions };
  Object.keys(otherOptions).forEach((key) => {
    params[key] = otherOptions[key];
  });
}

function getProxiesByRegex(params, regex) {
  return params.proxies.filter((e) => regex.test(e.name)).map((e) => e.name);
}
